#!/usr/bin/env python
# -*- coding: utf-8 -*-

from PyQt4.QtCore import *
from PyQt4.QtGui  import *
from customevents import *
from lyricscene   import LyricScene

import time

class LyricViewer(QGraphicsView):
    """
    """

    def __init__(self, lyric_scene):
        """
        
        Arguments:
        - `self`:
        - `scene`:
        """
        QGraphicsView.__init__(self, lyric_scene.scene)

        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        self.lyric_scene       = lyric_scene
        self.curr_time_ms      = 0
        # unit in pixel
        # scroll support
        self.scroll_speed      = 50
        self.last_hl_index     = 0
        self.scroll_from       = 0
        self.scroll_to         = 0
        self.scroll_begin_time = 0;
        self.scroll_timer      = QTimer()

        # 菜单支持
        self._init_menu()

        # on top always
        self.my_win_flags = self.windowFlags()
        self.setWindowFlags(self.my_win_flags | Qt.WindowStaysOnTopHint)

        # window title default to nil
        self.setWindowTitle("")

    def reset(self):
        """
        
        Arguments:
        - `self`:
        """
        if self.scroll_timer.isActive():
            self.scroll_timer.stop()

        self.curr_time_ms      = 0
        self.last_hl_index     = 0
        self.scroll_from       = 0
        self.scroll_to         = 0
        self.scroll_begin_time = 0

        self.verticalScrollBar().setValue(0)

    def _get_curr_vscroll_value(self):
        """
        
        Arguments:
        - `self`:
        """
        return self.verticalScrollBar().value()

    def _begin_scroll(self):
        """
        
        Arguments:
        - `self`:
        """
        if self.scroll_timer.isActive():
            self.scroll_timer.stop()

        self.scroll_from = self._get_curr_vscroll_value()
        self.scroll_to = self._get_target_scroll_size()

        # print "from %d to %d, idx from %d to %d" % (self.scroll_from, self.scroll_to,
        #                                             self.last_hl_index,
        #                                             self.lyric_scene.last_hl_index)

        self.last_hl_index = self.lyric_scene.last_hl_index

        # 如果滚动太长，直接设定目标值
        if abs(self.scroll_from - self.scroll_to) >= \
               (self.lyric_scene.lyric_font.pixelSize() \
                + self.lyric_scene.line_margin * 2) * 4:
            self.verticalScrollBar().setValue(self.scroll_to)
        else:
            self.scroll_begin_time = time.time()

            self.connect(self.scroll_timer, SIGNAL("timeout()"),
                         self._scroll_to)

            self.scroll_timer.start()

    def _scroll_to(self):
        """
        
        Arguments:
        - `self`:
        """
        time_diff = time.time() - self.scroll_begin_time
        if time_diff < 0.0:
            time_diff = 0.0

        ssize = time_diff * self.scroll_speed
        if self.scroll_from < self.scroll_to:
            real_ssize = self.scroll_from + ssize
            if real_ssize > self.scroll_to:
                real_ssize = self.scroll_to
        else:
            real_ssize = self.scroll_from - ssize
            if real_ssize < self.scroll_to:
                real_ssize = self.scroll_to

        self.verticalScrollBar().setValue(real_ssize)

        if real_ssize == self.scroll_to:
            self.scroll_timer.stop()

    # 自定义事件处理
    # 这些事件由其它模块发送到这里处理
    # 比如 amarok 那边换音乐，状态改变
    # 歌词选择好了，歌词下载好了，通过事件告诉
    # 主窗口
    def customEvent(self, event):
        """
        
        Arguments:
        - `self`:
        - `event`:
        """
        # LyricChangeEvent
        if event.type() == QEvent.User + 1:
            self.reset()
            self.lyric_scene.set_lyrics(event.lyric)
            self.setSceneRect(0, 0,
                              self.lyric_scene.max_width_no_margin,
                              self.lyric_scene.lyrics_height)
            # setup the title
            self.setWindowTitle("%s - %s" % (event.artist, event.title))
        # TimeChangeEvent
        elif event.type() == QEvent.User + 2:
            self.set_time_ms(event.time_ms)
        # StatusChangeEvent
        elif event.type() == QEvent.User + 3:
            pass

    # 禁止鼠标滚动
    def wheelEvent(self, event):
        pass

    def resizeEvent(self, event):
        """
        
        Arguments:
        - `self`:
        - `event`:
        """
        QGraphicsView.resizeEvent(self, event)

        if self.scroll_timer.isActive():
            self.scroll_timer.stop()

        self.verticalScrollBar().setValue(self._get_target_scroll_size())

    def _get_target_scroll_size(self):
        """
        
        Arguments:
        - `self`:
        """
        hl_idx = self.lyric_scene.last_hl_index
        if hl_idx >= 0 and hl_idx < len(self.lyric_scene.text_items):
            item = self.lyric_scene.text_items[hl_idx]
            y = item.y()
            h = self.height()
            y = y - (h / 2.0)
            if y < 0.0:
                y = 0.0
            return y
        return 0

    # 禁止键盘滚动
    def keyPressEvent(self, event):
        """
        
        Arguments:
        - `self`:
        - `event`:
        """
        pass

    def keyReleaseEvent(self, event):
        """
        
        Arguments:
        - `self`:
        - `event`:
        """
        pass

    def set_time_ms(self, time_ms):
        """ 根据时间比例滚动到合适的位置
        
        Arguments:
        - `self`:
        - `time_ms`:
        """
        self.curr_time_ms = time_ms
        self.lyric_scene.set_time_ms(time_ms)
        if self.last_hl_index != self.lyric_scene.last_hl_index:
            self._begin_scroll()

    def start(self):
        """
        
        Arguments:
        - `self`:
        """
        self.begin_time = time.time()
        self.timer = QTimer()
        self.connect(self.timer, SIGNAL("timeout()"),
                     self._timeout)
        self.timer.start(30)

    def _timeout(self):
        """
        
        Arguments:
        - `self`:
        """
        diff = time.time() - self.begin_time
        if diff < 0.0:
            diff = 0.0

        ms = int(diff * 1000)

        self.set_time_ms(ms)

    def _init_menu(self):
        """
        
        Arguments:
        - `self`:
        """
        self.menu = QMenu()

        # about
        self.about_action = QAction(QIcon("icon/logo.png"), "关于", self)
        self.menu.addAction(self.about_action)

        # about qt
        self.about_qt_action = QAction(QIcon("icon/qt.png"), "关于 Qt", self)
        self.menu.addAction(self.about_qt_action)

        # connect handlers
        self.connect(self.about_action, SIGNAL("triggered()"),
                     self.about_action_)
        self.connect(self.about_qt_action, SIGNAL("triggered()"),
                     self.about_qt_action_)

    def about_action_(self):
        """
        
        Arguments:
        - `self`:
        """
        QMessageBox.about(self,
                          '关于 lyricplayer',
                          '''
version:     lyricplayer 0.1
description: amarok 的歌词播放器
author:      偶像的黄昏
license:     MIT
bug report:  pxqlinux@gmail.com''')

    def about_qt_action_(self):
        """
        
        Arguments:
        - `self`:
        """
        QMessageBox.aboutQt(self, '关于 Qt')

    def contextMenuEvent(self, event):
        """
        
        Arguments:
        - `self`:
        - `event`:
        """
        self.menu.popup(event.globalPos())

if __name__ == '__main__':
    import sys

    app = QApplication(sys.argv)
    scene = QGraphicsScene()
    scene.addText("hello kitty")
    view = LyricViewer(scene)
    view.show()
    sys.exit(app.exec_())
